home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / t_gen / t_gen.lha / Compilers-Scanners.st < prev    next >
Text File  |  1993-07-19  |  34KB  |  1,259 lines

  1. Object subclass: #AbstractScanner
  2.     instanceVariableNames: 'source nextChar token tokenType buffer '
  3.     classVariableNames: ''
  4.     poolDictionaries: ''
  5.     category: 'Compilers-Scanners'!
  6. AbstractScanner comment:
  7. '=================================================
  8.     Copyright (c) 1992 by Justin O. Graver.
  9.     All rights reserved (with exceptions).
  10.     For complete information evaluate "Object tgenCopyright."
  11. =================================================
  12.  
  13. I scan a source string and break it up into tokens using mechanisms provided in concrete subclasses.
  14.  
  15. Instance Variables:
  16.     source            <ReadStream> - character input stream.
  17.     nextChar        <Character + UndefinedObject> - one-character lookahead buffer for source, nil if no input left.
  18.     token            <String> - current token buffer.
  19.     tokenType    <String + Symbol> - current token type buffer.
  20.     buffer            <WriteStream> - character accumulation buffer for tokens.
  21. '!
  22.  
  23.  
  24. !AbstractScanner methodsFor: 'initialization'!
  25.  
  26. init
  27.  
  28.     self buffer: (RetractableWriteStream on: (String new: 32))!
  29.  
  30. reset
  31.     "Reset the initial state of the scanner before scanning a new source."
  32.  
  33.     self buffer reset.
  34.     self token: nil.
  35.     self tokenType: nil.
  36.     self nextChar: nil!
  37.  
  38. scanSource: aString 
  39.     "Convert the input string to a read stream and scan the first token."
  40.  
  41.     self reset.
  42.     self source: (RetractableReadStream on: aString).
  43.     self nextChar: self source next.
  44.     self scanToken! !
  45.  
  46. !AbstractScanner methodsFor: 'state accessing'!
  47.  
  48. buffer
  49.  
  50.     ^buffer!
  51.  
  52. buffer: argument 
  53.  
  54.     buffer := argument!
  55.  
  56. nextChar
  57.  
  58.     ^nextChar!
  59.  
  60. nextChar: argument 
  61.  
  62.     nextChar := argument!
  63.  
  64. source
  65.  
  66.     ^source!
  67.  
  68. source: argument 
  69.  
  70.     source := argument!
  71.  
  72. token
  73.  
  74.     ^token!
  75.  
  76. token: argument 
  77.  
  78.     token := argument!
  79.  
  80. tokenType
  81.  
  82.     ^tokenType!
  83.  
  84. tokenType: argument 
  85.  
  86.     tokenType := argument! !
  87.  
  88. !AbstractScanner methodsFor: 'scanning'!
  89.  
  90. backspaceSource
  91.     "When the source is at the end, 'source current' is the last character."
  92.  
  93.     self atEnd ifFalse: [self source backspace].
  94.     self nextChar: self source current!
  95.  
  96. getNextChar
  97.     "Source will answer an empty string when no more input is available. 
  98.     Subclasses may override this to avoid unnecessary buffering."
  99.  
  100.     self buffer nextPut: self nextChar.
  101.     self nextChar: self source next!
  102.  
  103. putBackChar
  104.     "Remove the last character in the buffer and backspace the source. 
  105.     Subclasses may override this to avoid unnecessary buffering."
  106.  
  107.     self buffer backspace.
  108.     self backspaceSource!
  109.  
  110. scanToken
  111.     "Subclasses must compute values for token and tokenType here."
  112.  
  113.     self subclassResponsibility!
  114.  
  115. signalEndOfInput
  116.     "Set scanner to the end-of-input state."
  117.  
  118.     self tokenType: self endOfInputTokenType.
  119.     self token: self endOfInputToken! !
  120.  
  121. !AbstractScanner methodsFor: 'testing'!
  122.  
  123. atEnd
  124.  
  125.     ^self nextChar = self endOfInputToken! !
  126.  
  127. !AbstractScanner methodsFor: 'accessing'!
  128.  
  129. contents
  130.  
  131.     ^self source contents!
  132.  
  133. endOfInputToken
  134.     "Answer a token representing the end of the input."
  135.  
  136.     self subclassResponsibility!
  137.  
  138. endOfInputTokenType
  139.     "Answer the token type representing the end of the input."
  140.  
  141.     self subclassResponsibility!
  142.  
  143. errorPosition
  144.     "Answer the source position of the last acceptable character."
  145.  
  146.     ^source position + (self atEnd
  147.             ifTrue: [1]
  148.             ifFalse: [0]) max: 1!
  149.  
  150. position
  151.  
  152.     ^self source position! !
  153. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  154.  
  155. AbstractScanner class
  156.     instanceVariableNames: ''!
  157.  
  158.  
  159. !AbstractScanner class methodsFor: 'instance creation'!
  160.  
  161. new
  162.  
  163.     ^super new init!
  164.  
  165. scanFrom: aString 
  166.  
  167.     | newScanner |
  168.     newScanner := self new.
  169.     newScanner scanSource: aString.
  170.     ^newScanner! !
  171.  
  172. AbstractScanner subclass: #FSABasedScanner
  173.     instanceVariableNames: 'fsa '
  174.     classVariableNames: ''
  175.     poolDictionaries: ''
  176.     category: 'Compilers-Scanners'!
  177. FSABasedScanner comment:
  178. '=================================================
  179.     Copyright (c) 1992 by Justin O. Graver.
  180.     All rights reserved (with exceptions).
  181.     For complete information evaluate "Object tgenCopyright."
  182. =================================================
  183.  
  184. I am an abstract class of scanner that scans a source string and breaks it up into tokens using a minimal deterministic finite-state automata (FSA).  Each token is also given a type by its associated final state in the FSA.  Specific FSAs are stored in class instance variables of my concrete subclasses.
  185.  
  186. Instance Variables:
  187.     fsa                <FSAState> - a local reference to the token recognizer, in minimal deterministic form, for this class of scanner.
  188. '!
  189.  
  190.  
  191. !FSABasedScanner methodsFor: 'state accessing'!
  192.  
  193. fsa
  194.  
  195.     ^fsa!
  196.  
  197. fsa: argument 
  198.  
  199.     fsa := argument! !
  200.  
  201. !FSABasedScanner methodsFor: 'scanning directives'!
  202.  
  203. compactDoubleApostrophes
  204.     "Compact all two apostrophe sequences in my current token into a single 
  205.     apostrophe."
  206.  
  207.     | readStream writeStream ch nextCh |
  208.     readStream := ReadStream on: self token.
  209.     writeStream := WriteStream on: (String new: 20).
  210.     [readStream atEnd]
  211.         whileFalse: 
  212.             [writeStream nextPut: (ch := readStream next).
  213.             (ch = $' and: [(nextCh := readStream peek) notNil and: [nextCh = $']])
  214.                 ifTrue: [readStream skip: 1]].
  215.     self token: writeStream contents!
  216.  
  217. ignoreComment
  218.  
  219.     self scanToken!
  220.  
  221. ignoreDelimiter
  222.  
  223.     self scanToken! !
  224.  
  225. !FSABasedScanner methodsFor: 'accessing'!
  226.  
  227. endOfInputToken
  228.     "Answer a token representing the end of the input."
  229.  
  230.     ^Character endOfInput!
  231.  
  232. endOfInputTokenType
  233.     "Answer the token type representing the end of the input."
  234.  
  235.     ^self endOfInputToken!
  236.  
  237. myFsa
  238.  
  239.     ^self class fsa!
  240.  
  241. startState
  242.  
  243.     ^self fsa! !
  244.  
  245. !FSABasedScanner methodsFor: 'scanning'!
  246.  
  247. scanToken
  248.     "Scan the next token and compute its token type."
  249.  
  250.     | state nextState tok typeAction |
  251.     self atEnd
  252.         ifTrue: [self signalEndOfInput]
  253.         ifFalse: 
  254.             [state := self startState.
  255.             [(nextState := self at: state transitionFor: self nextChar) isNil]
  256.                 whileFalse: 
  257.                     [state := nextState.
  258.                     self getNextChar].
  259.             tok := self buffer contents.
  260.             typeAction := self at: state tokenTypeAndActionFor: tok.
  261.             self tokenType: typeAction type.
  262.             self token: tok.
  263.             self buffer reset.
  264.             typeAction action notNil ifTrue: [self perform: typeAction action]]! !
  265.  
  266. !FSABasedScanner methodsFor: 'initialization'!
  267.  
  268. init
  269.  
  270.     super init.
  271.     self fsa: self myFsa! !
  272.  
  273. !FSABasedScanner methodsFor: 'scanner generation'!
  274.  
  275. classInitializationMethodTextForClassNamed: name spec: tokenSpec 
  276.  
  277.     ^self subclassResponsibility!
  278.  
  279. createScannerClassNamed: name category: category spec: tokenSpec 
  280.  
  281.     | scannerClass |
  282.     scannerClass := self defaultScannerClass
  283.                 subclass: name asSymbol
  284.                 instanceVariableNames: ''
  285.                 classVariableNames: ''
  286.                 poolDictionaries: ''
  287.                 category: category.
  288.     scannerClass comment: self generatedScannerClassComment.
  289.     scannerClass class compile: (self classInitializationMethodTextForClassNamed: name spec: tokenSpec)
  290.         classified: 'class initialization'.
  291.     scannerClass initialize.
  292.     ^scannerClass!
  293.  
  294. generatedScannerClassComment
  295.  
  296.     ^'This scanner class was automatically generated by ', TranslatorGenerator versionName , '.'!
  297.  
  298. defaultScannerClass
  299.  
  300.     ^self class!
  301.  
  302. defaultOptimizedScannerClass
  303.  
  304.     ^OptimizedScanner! !
  305.  
  306. !FSABasedScanner methodsFor: 'converting'!
  307.  
  308. fastScanner
  309.  
  310.     ^self defaultOptimizedScannerClass buildFrom: self! !
  311.  
  312. !FSABasedScanner methodsFor: 'private'!
  313.  
  314. at: state tokenTypeAndActionFor: tok 
  315.  
  316.     ^state tokenTypeAndActionFor: tok!
  317.  
  318. at: state transitionFor: char 
  319.  
  320.     ^state transitionFor: char! !
  321. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  322.  
  323. FSABasedScanner class
  324.     instanceVariableNames: 'fsa '!
  325.  
  326.  
  327. !FSABasedScanner class methodsFor: 'state accessing'!
  328.  
  329. fsa
  330.  
  331.     ^fsa!
  332.  
  333. fsa: argument 
  334.  
  335.     fsa := argument! !
  336.  
  337. !FSABasedScanner class methodsFor: 'class initialization'!
  338.  
  339. initialize
  340.     "Concrete subclasses must somehow provide a fsa. Subclasses created by 
  341.     automatic means may simply 'plug-in' a dynamically computed fsa. However, if a 
  342.     class that can be filed-out is desired then it is worthwhile to override this 
  343.     initialization method with one that can build the appropriate fsa directly."
  344.     "FSABasedScanner initialize"
  345.  
  346.     self fsa: nil! !
  347.  
  348. FSABasedScanner subclass: #FSABasedLookaheadScanner
  349.     instanceVariableNames: 'savePosition '
  350.     classVariableNames: ''
  351.     poolDictionaries: ''
  352.     category: 'Compilers-Scanners'!
  353. FSABasedLookaheadScanner comment:
  354. '=================================================
  355.     Copyright (c) 1992 by Justin O. Graver.
  356.     All rights reserved (with exceptions).
  357.     For complete information evaluate "Object tgenCopyright."
  358. =================================================
  359.  
  360. This is an abstract class for scanners with lookahead.
  361.  
  362. Instance Variables:
  363.     savePosition <Integer> - pointer into input source for error notification.'!
  364.  
  365.  
  366. !FSABasedLookaheadScanner methodsFor: 'initialization'!
  367.  
  368. reset
  369.     "Reset the initial state of the scanner before scanning a new source."
  370.  
  371.     super reset.
  372.     self savePosition: 0! !
  373.  
  374.  
  375. !FSABasedLookaheadScanner methodsFor: 'state accessing'!
  376.  
  377. savePosition
  378.  
  379.     ^savePosition!
  380.  
  381. savePosition: argument 
  382.  
  383.     savePosition := argument! !
  384.  
  385. !FSABasedLookaheadScanner methodsFor: 'accessing'!
  386.  
  387. errorPosition
  388.     "Answer the source position of the last acceptable character."
  389.  
  390.     ^self savePosition max: 1! !
  391.  
  392.  
  393. FSABasedLookaheadScanner subclass: #FSABasedScannerWithTwoTokenLookahead
  394.     instanceVariableNames: 'stateStack saveState saveChar '
  395.     classVariableNames: ''
  396.     poolDictionaries: ''
  397.     category: 'Compilers-Scanners'!
  398.  
  399. FSABasedScannerWithTwoTokenLookahead comment:
  400. '=================================================
  401.     Copyright (c) 1992 by Justin O. Graver.
  402.     All rights reserved (with exceptions).
  403.     For complete information evaluate "Object tgenCopyright."
  404. =================================================
  405.  
  406. This class provides a scanner with simple two-token lookahead.
  407.  
  408. Instance Variables:
  409.     stateStack    <Stack> - primary state stack for scanning tokens.
  410.     saveState    <Integer> - pointer into input source for error notification.
  411.     saveChar    <Character> - pointer into input source for error notification.'!
  412.  
  413. !FSABasedScannerWithTwoTokenLookahead methodsFor: 'scanner generation'!
  414.  
  415. defaultOptimizedScannerClass
  416.  
  417.     ^OptimizedScannerWithTwoTokenLookahead! !
  418.  
  419. !FSABasedScannerWithTwoTokenLookahead methodsFor: 'scanning'!
  420.  
  421. checkForTokenIn: newStateStack buffer: charBuffer 
  422.     "Scan the input using the arguments. Answer true if a legal token (or no illegal token) was 
  423.     found and false otherwise."
  424.  
  425.     | nextState |
  426.     self atEnd
  427.         ifFalse: 
  428.             [newStateStack push: self startState.
  429.             "look for longest possible token"
  430.             [(nextState := newStateStack top transitionFor: self nextChar ifNone: [nil]) isNil]
  431.                 whileFalse: 
  432.                     [newStateStack push: nextState.
  433.                     "getNextChar for local vars"
  434.                     charBuffer nextPut: self nextChar.
  435.                     self nextChar: self source next].
  436.             "save the current position for error notification"
  437.             self savePosition: self position + (self atEnd ifTrue: [1] ifFalse: [0]).
  438.             newStateStack top isFSAFinalState
  439.                 ifFalse: 
  440.                     [self saveChar: self nextChar.
  441.                     self saveState: newStateStack top.
  442.                     "backup to the previous final state or to the start state"
  443.                     [newStateStack size = 1 or: [newStateStack top isFSAFinalState]]
  444.                         whileFalse: 
  445.                             [newStateStack pop.
  446.                             "putBackChar for local vars"
  447.                             charBuffer backspace.
  448.                             self backspaceSource].
  449.                     newStateStack size = 1 ifTrue: 
  450.                         ["backed up to the start state"
  451.                         self stateStack == newStateStack
  452.                             ifTrue: 
  453.                                 ["this is the first token, so signal an error (abort and return)"
  454.                                 self saveState transitionFor: self saveChar]
  455.                             ifFalse: 
  456.                                 ["we may be able to backup in the previous token"
  457.                                 ^false]]]].
  458.     ^true!
  459.  
  460. scanToken
  461.     "Scan the next token and compute its token type."
  462.  
  463.     | tok typeAction newStateStack charBuffer |
  464.     newStateStack := Stack new.
  465.     charBuffer := RetractableWriteStream on: (String new: 32).
  466.     (self checkForTokenIn: newStateStack buffer: charBuffer)
  467.         ifTrue: 
  468.             ["either a legal token or the end on input was found"
  469.             self stateStack isEmpty ifTrue: [self atEnd
  470.                     ifTrue: [^self signalEndOfInput]
  471.                     ifFalse: [self error: 'no more vaild tokens']].
  472.             tok := self buffer contents.
  473.             typeAction := self stateStack top tokenTypeAndActionFor: tok.
  474.             self tokenType: typeAction type.
  475.             self token: tok.
  476.             self buffer: charBuffer.
  477.             self stateStack: newStateStack.
  478.             typeAction action notNil ifTrue: [self perform: typeAction action]]
  479.         ifFalse: 
  480.             ["an illegal token was found, try to look for earlier final state in current token buffers"
  481.             charBuffer size timesRepeat: 
  482.                 ["put back illegal token chars"
  483.                 self backspaceSource].
  484.             "backup in current token to next smallest legal token"
  485.             [self stateStack size = 1
  486.                 or: 
  487.                     [self stateStack pop.
  488.                     self putBackChar.
  489.                     self stateStack top isFSAFinalState]] whileFalse.
  490.             self stateStack size = 1
  491.                 ifTrue: 
  492.                     ["no smaller legal token so signal error"
  493.                     self saveState transitionFor: self saveChar]
  494.                 ifFalse: 
  495.                     ["try again"
  496.                     self scanToken]]! !
  497.  
  498. !FSABasedScannerWithTwoTokenLookahead methodsFor: 'state accessing'!
  499.  
  500. saveChar
  501.  
  502.     ^saveChar!
  503.  
  504. saveChar: argument 
  505.  
  506.     saveChar := argument!
  507.  
  508. saveState
  509.  
  510.     ^saveState!
  511.  
  512. saveState: argument 
  513.  
  514.     saveState := argument!
  515.  
  516. stateStack
  517.  
  518.     ^stateStack!
  519.  
  520. stateStack: argument 
  521.  
  522.     stateStack := argument! !
  523.  
  524. !FSABasedScannerWithTwoTokenLookahead methodsFor: 'initialization'!
  525.  
  526. reset
  527.     "Reset the initial state of the scanner before scanning a new source."
  528.  
  529.     super reset.
  530.     self stateStack: Stack new!
  531.  
  532. scanSource: aString 
  533.     "Convert the input string to a read stream and scan the first token."
  534.  
  535.     self reset.
  536.     self source: (RetractableReadStream on: aString).
  537.     self nextChar: self source next.
  538.     self checkForTokenIn: self stateStack buffer: self buffer.
  539.     self scanToken! !
  540.  
  541.  
  542. FSABasedLookaheadScanner subclass: #FSABasedScannerWithOneTokenLookahead
  543.     instanceVariableNames: ''
  544.     classVariableNames: ''
  545.     poolDictionaries: ''
  546.     category: 'Compilers-Scanners'!
  547.  
  548. FSABasedScannerWithOneTokenLookahead comment:
  549. '=================================================
  550.     Copyright (c) 1992 by Justin O. Graver.
  551.     All rights reserved (with exceptions).
  552.     For complete information evaluate "Object tgenCopyright."
  553. =================================================
  554.  
  555. This class provides a scanner with simple one-token lookahead.  '!
  556.  
  557.  
  558. !FSABasedScannerWithOneTokenLookahead methodsFor: 'scanner generation'!
  559.  
  560. defaultOptimizedScannerClass
  561.  
  562.     ^OptimizedScannerWithOneTokenLookahead! !
  563.  
  564. !FSABasedScannerWithOneTokenLookahead methodsFor: 'scanning'!
  565.  
  566. scanToken
  567.     "Scan the next token and compute its token type."
  568.  
  569.     | nextState tok typeAction stateStack saveChar saveState |
  570.     stateStack := Stack new.
  571.     self atEnd
  572.         ifTrue: [self signalEndOfInput]
  573.         ifFalse: 
  574.             [stateStack push: self startState.
  575.             [(nextState := stateStack top transitionFor: self nextChar ifNone: [nil]) isNil]
  576.                 whileFalse: 
  577.                     [stateStack push: nextState.
  578.                     self getNextChar].
  579.             "save the current position for error notification"
  580.             self savePosition: self position + (self atEnd ifTrue: [1] ifFalse: [0]).
  581.             stateStack top isFSAFinalState
  582.                 ifFalse: 
  583.                     [saveChar := self nextChar.
  584.                     saveState := stateStack top.
  585.                     "backup to the previous final state or to the start state"
  586.                     [stateStack size = 1 or: [stateStack top isFSAFinalState]]
  587.                         whileFalse: 
  588.                             [stateStack pop.
  589.                             self putBackChar].
  590.                     stateStack size = 1 ifTrue: 
  591.                         ["backed up to the start state so signal an error"
  592.                         saveState transitionFor: saveChar]].
  593.             "answer the newly scanned token"
  594.             tok := self buffer contents.
  595.             typeAction := stateStack top tokenTypeAndActionFor: tok.
  596.             self tokenType: typeAction type.
  597.             self token: tok.
  598.             self buffer reset.
  599.             typeAction action notNil ifTrue: [self perform: typeAction action]]! !
  600.  
  601.  
  602. FSABasedScanner subclass: #OptimizedScanner
  603.     instanceVariableNames: 'finalStateTable '
  604.     classVariableNames: 'NoTransitionSignal '
  605.     poolDictionaries: ''
  606.     category: 'Compilers-Scanners'!
  607.  
  608. OptimizedScanner comment:
  609. '=================================================
  610.     Copyright (c) 1992 by Justin O. Graver.
  611.     All rights reserved (with exceptions).
  612.     For complete information evaluate "Object tgenCopyright."
  613. =================================================
  614.  
  615. I am an abstract class of scanner that scans a source string and breaks it up into tokens
  616. using a table created by converting FSA to integer.
  617.  
  618. instance Variables:
  619.     finalStateTable        - a table that maps integer ( represented as final state ) to 
  620.                            literal tokens and token classes.
  621. '!
  622.  
  623.  
  624. !OptimizedScanner methodsFor: 'converting'!
  625.  
  626. assignNextIDAfter: id toSuccessorOf: state 
  627.     "I try to assing a number to fsa in order to create a fsa table."
  628.  
  629.     | nextID nextState |
  630.     nextID := id + 1.
  631.     state edgeLabelMap
  632.         associationsDo: 
  633.             [:assoc | 
  634.             nextState := assoc value.
  635.             nextState stateID isNil
  636.                 ifTrue: 
  637.                     [nextState stateID: nextID.
  638.                     nextState isFSAFinalState ifTrue: [(finalStateTable includes: nextState)
  639.                             ifFalse: [finalStateTable at: nextID put: nextState]].
  640.                     nextID := self assignNextIDAfter: nextID toSuccessorOf: nextState]].
  641.     ^nextID!
  642.  
  643. changeFSAToObjectTable: fsaState 
  644.  
  645.     | sizePlusOne objectTable  |
  646.     fsaState stateID notNil ifTrue: [fsaState nilOutStateIDs].
  647.     fsaState stateID:  self startState.
  648.     self finalStateTable: Dictionary new.
  649.     sizePlusOne := self assignNextIDAfter: self startState toSuccessorOf: fsaState.
  650.     objectTable := Array new: sizePlusOne - 1.
  651.     self convert: fsaState to: objectTable.
  652.     self modifyFSAFinalStates: sizePlusOne - 1.        "convert Dictionary to Array for speed"
  653.     ^objectTable!
  654.  
  655. convert: state to: objectTable 
  656.     "I try to create a table that maps state ( represented by integer ) to state"
  657.  
  658.     | arr nextState |
  659.     arr := Array new: 127.
  660.     objectTable at: state stateID put: arr.
  661.     state edgeLabelMap
  662.         associationsDo: 
  663.             [:assoc | 
  664.             nextState := assoc value.
  665.             (objectTable at: nextState stateID) isNil ifTrue: [self convert: nextState to: objectTable].
  666.             arr at: assoc key asInteger put: nextState stateID].
  667.     ^objectTable!
  668.  
  669. convertToTable: fsaScanner 
  670.  
  671.     self fsa: (self changeFSAToObjectTable: fsaScanner fsa)!
  672.  
  673. modifyFSAFinalStates: index 
  674.     "Convert Dictionary and its values to Array of Array"
  675.  
  676.     | tokenSet table |
  677.     table := Array new: index.
  678.     finalStateTable do: 
  679.         [:st | 
  680.         tokenSet := Array new: 2.
  681.         tokenSet at: 1 put: st literalTokens asOrderedCollection asArray; at: 2 put: st tokenClasses asArray.
  682.         table at: st stateID put: tokenSet].
  683.     self finalStateTable: table! !
  684.  
  685. !OptimizedScanner methodsFor: 'private'!
  686.  
  687. at: state transitionFor: char 
  688.  
  689.     | value |
  690.     (value := (fsa at: state)
  691.                 at: char asInteger) isNil ifTrue: [(finalStateTable at: state) isNil ifTrue: [self raiseNoTransitionExceptionErrorString: (char == self endOfInputToken
  692.                     ifTrue: [self endOfInputErrorString]
  693.                     ifFalse: [self standardErrorString , '''' , char printString , ''''])]].
  694.     ^value! !
  695.  
  696. !OptimizedScanner methodsFor: 'initialization'!
  697.  
  698. init
  699.  
  700.     super init.
  701.     self finalStateTable: self myFinalStateTable! !
  702.  
  703. !OptimizedScanner methodsFor: 'state accessing'!
  704.  
  705. finalStateTable
  706.  
  707.     ^finalStateTable!
  708.  
  709. finalStateTable: arg 
  710.  
  711.     finalStateTable := arg! !
  712.  
  713. !OptimizedScanner methodsFor: 'accessing'!
  714.  
  715. myFinalStateTable
  716.  
  717.     ^self class finalStateTable!
  718.  
  719. startState
  720.  
  721.     ^1! !
  722.  
  723. !OptimizedScanner methodsFor: 'exception handling'!
  724.  
  725. endOfInputErrorString
  726.  
  727.     ^'end of input encountered'!
  728.  
  729. raiseNoTransitionExceptionErrorString: aString 
  730.  
  731.     self class noTransitionSignal raiseErrorString: aString!
  732.  
  733. standardErrorString
  734.  
  735.     ^'illegal character encountered:  '! !
  736.  
  737. !OptimizedScanner methodsFor: 'testing'!
  738.  
  739. atEnd
  740.  
  741.     ^nextChar == self endOfInputToken        "end-of-file character"! !
  742.  
  743. !OptimizedScanner methodsFor: 'reconstructing'!
  744.  
  745. reconstructFinalStateTableOn: aStream 
  746.  
  747.     aStream nextPutAll: 'table := '.
  748.     finalStateTable reconstructOn: aStream.
  749.     aStream
  750.         period;
  751.         crtab;
  752.         nextPutAll: 'self constructFinalStateTable: table'!
  753.  
  754. reconstructFSAOn: aStream 
  755.  
  756.     aStream nextPutAll: 'self fsa: '.
  757.     fsa reconstructOn: aStream.
  758.     aStream period; crtab!
  759.  
  760. reconstructOn: aStream 
  761.     "Recreate fsa and final state tables"
  762.  
  763.     self reconstructFSAOn: aStream.
  764.     self reconstructFinalStateTableOn: aStream! !
  765.  
  766. !OptimizedScanner methodsFor: 'scanner generation'!
  767.  
  768. classInitializationMethodTextForClassNamed: name spec: tokenSpec 
  769.     | ws |
  770.     ws := WriteStream on: (String new: 2048).
  771.     ws
  772.         nextPutAll: 'initialize';
  773.         crtab;
  774.         nextPut: $";
  775.         nextPutAll: name;
  776.         nextPutAll: ' initialize"';
  777.         crtab;
  778.         nextPut: $".
  779.     tokenSpec do: 
  780.         [:ch | 
  781.         "double embedded double-quote characters"
  782.         ws nextPut: ch.
  783.         ch = $" ifTrue: [ws nextPut: $"]].
  784.     ws
  785.         nextPut: $";
  786.         cr;
  787.         crtab;
  788.         nextPutAll: '| table |';
  789.         crtab.
  790.     self reconstructOn: ws.
  791.     ^ws contents! !
  792.  
  793. !OptimizedScanner methodsFor: 'scanning'!
  794.  
  795. at: state tokenTypeAndActionFor: aString 
  796.     "The current implementation does not handle overlapping token classes. Hence, a final state 
  797.     can only represent a literal or a single token class. Therefore, if not a literal then it must be 
  798.     the token class."
  799.  
  800.     | tc |
  801.     (((finalStateTable at: state)
  802.         at: 1)
  803.         includes: aString)
  804.         ifTrue: [^TokenTypeActionHolder type: aString action: nil].
  805.     tc := ((finalStateTable at: state)
  806.                 at: 2) first .
  807.     ^TokenTypeActionHolder type: tc tokenType action: tc action!
  808.  
  809. getNextChar
  810.     "Source will answer an eof char when no more input is available. 
  811.     Subclasses may override this to avoid unnecessary buffering."
  812.  
  813.     buffer nextPut: nextChar.
  814.     nextChar := source next!
  815.  
  816. signalEndOfInput
  817.     "Set scanner to the end-of-input state."
  818.  
  819.     tokenType := token := self endOfInputToken! !
  820. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  821.  
  822. OptimizedScanner class
  823.     instanceVariableNames: 'finalStateTable tokenTable '!
  824.  
  825.  
  826. !OptimizedScanner class methodsFor: 'state accessing'!
  827.  
  828. finalStateTable
  829.  
  830.     ^finalStateTable!
  831.  
  832. finalStateTable: arg 
  833.  
  834.     finalStateTable := arg!
  835.  
  836. noTransitionSignal
  837.  
  838.     ^NoTransitionSignal!
  839.  
  840. noTransitionSignal: arg 
  841.  
  842.     NoTransitionSignal := arg!
  843.  
  844. tokenTable
  845.  
  846.     ^tokenTable!
  847.  
  848. tokenTable: arg 
  849.  
  850.     tokenTable := arg! !
  851.  
  852. !OptimizedScanner class methodsFor: 'class initialization'!
  853.  
  854. initialize
  855.     "OptimizedScanner initialize"
  856.  
  857.     self noTransitionSignal: (Signal new nameClass: self message: #noTransitionSymbol).! !
  858.  
  859. !OptimizedScanner class methodsFor: 'reconstructing'!
  860.  
  861. constructFinalStateTable: arg 
  862.  
  863.     finalStateTable := Array new: arg size.
  864.     1 to: arg size do: [:index | finalStateTable at: index put: ((arg at: index) isNil
  865.                 ifTrue: [nil]
  866.                 ifFalse: [Array with: ((arg at: index)
  867.                             at: 1)
  868.                         with: (self constructTokenClassification: ((arg at: index)
  869.                                     at: 2))])]!
  870.  
  871. constructTokenClassification: aCollection 
  872.  
  873.     | tc ea arr |
  874.     aCollection size == 1
  875.         ifTrue: 
  876.             [tc := aCollection first.
  877.             ^Array with: (TokenClassification
  878.                     tokenType: (tc at: 1)
  879.                     action: (tc at: 2))]
  880.         ifFalse: 
  881.             [arr := Array new: aCollection size.
  882.             1 to: aCollection size do: 
  883.                 [:index | 
  884.                 ea := aCollection at: index.
  885.                 arr at: index put: (TokenClassification
  886.                         tokenType: (ea at: 1)
  887.                         action: (ea at: 2))].
  888.             ^arr]! !
  889.  
  890. !OptimizedScanner class methodsFor: 'instance creation'!
  891.  
  892. buildFrom: fsaScanner
  893.  
  894.     ^self new convertToTable: fsaScanner! !
  895.  
  896.  
  897. OptimizedScanner subclass: #OptimizedLookaheadScanner
  898.     instanceVariableNames: 'savePosition '
  899.     classVariableNames: ''
  900.     poolDictionaries: ''
  901.     category: 'Compilers-Scanners'!
  902. OptimizedLookaheadScanner comment:
  903. '=================================================
  904.     Copyright (c) 1992 by Justin O. Graver.
  905.     All rights reserved (with exceptions).
  906.     For complete information evaluate "Object tgenCopyright."
  907. =================================================
  908.  
  909. This is an abstract class for table-based optimized scanners with lookahead.
  910.  
  911. Instance Variables:
  912.     savePosition <Integer> - pointer into input source for error notification.'!
  913.  
  914.  
  915. !OptimizedLookaheadScanner methodsFor: 'accessing'!
  916.  
  917. errorPosition
  918.     "Answer the source position of the last acceptable character."
  919.  
  920.     ^self savePosition max: 1! !
  921.  
  922. !OptimizedLookaheadScanner methodsFor: 'initialization'!
  923.  
  924. reset
  925.     "Reset the initial state of the scanner before scanning a new source."
  926.  
  927.     super reset.
  928.     self savePosition: 0! !
  929.  
  930. !OptimizedLookaheadScanner methodsFor: 'state accessing'!
  931.  
  932. savePosition
  933.  
  934.     ^savePosition!
  935.  
  936. savePosition: argument 
  937.  
  938.     savePosition := argument! !
  939.  
  940. !OptimizedLookaheadScanner methodsFor: 'testing'!
  941.  
  942. isFSAFinalState: aState
  943.     "Answer true if aState is a final state, false otherwise."
  944.  
  945.     ^(self finalStateTable at: aState) notNil! !
  946.  
  947.  
  948. AbstractScanner subclass: #HandCodedScanner
  949.     instanceVariableNames: 'charTypeTable '
  950.     classVariableNames: ''
  951.     poolDictionaries: ''
  952.     category: 'Compilers-Scanners'!
  953. HandCodedScanner comment:
  954. '=================================================
  955.     Copyright (c) 1992 by Justin O. Graver.
  956.     All rights reserved (with exceptions).
  957.     For complete information evaluate "Object tgenCopyright."
  958. =================================================
  959.  
  960. I am an abstract class of scanner that scans a source string and breaks it up into tokens using a character type table and hand-coded scanner methods.  Specific type tables are stored in class instance variables of my concrete subclasses.
  961.  
  962. Instance Variables:
  963.     charTypeTable    <Array of: Symbol> - a local reference to the type table for this class of scanner; the ascii value of each character is mapped to a symbol token type.
  964. '!
  965.  
  966.  
  967. !HandCodedScanner methodsFor: 'state accessing'!
  968.  
  969. charTypeTable
  970.  
  971.     ^charTypeTable!
  972.  
  973. charTypeTable: argument 
  974.  
  975.     charTypeTable := argument! !
  976.  
  977. !HandCodedScanner methodsFor: 'initialization'!
  978.  
  979. init
  980.  
  981.     super init.
  982.     self charTypeTable: self myTypeTable! !
  983.  
  984. !HandCodedScanner methodsFor: 'accessing'!
  985.  
  986. endOfInputToken
  987.     "Answer a token representing the end of the input."
  988.  
  989.     ^nil!
  990.  
  991. endOfInputTokenType
  992.     "Answer the token type representing the end of the input."
  993.  
  994.     ^#doIt!
  995.  
  996. myTypeTable
  997.  
  998.     ^self class charTypeTable! !
  999.  
  1000. !HandCodedScanner methodsFor: 'testing'!
  1001.  
  1002. atStartOfComplexToken
  1003.     "Answer true if the first character of the tokenType is an $x and false otherwise."
  1004.  
  1005.     ^(self tokenType at: 1)
  1006.         = $x! !
  1007.  
  1008. !HandCodedScanner methodsFor: 'scanning'!
  1009.  
  1010. scanToken
  1011.     "Scan the next token and compute its token type.  This may be 
  1012.     overridden in subclasses for efficiency and customization."
  1013.  
  1014.     
  1015.     [self atEnd ifTrue: [^self signalEndOfInput].
  1016.     self tokenType: (self charTypeTable at: self nextChar asInteger).
  1017.     self tokenType == #xDelimiter]
  1018.         whileTrue: 
  1019.             ["Skip delimiters fast, there almost always is one."
  1020.             self getNextChar].
  1021.     self atStartOfComplexToken
  1022.         ifTrue: 
  1023.             ["perform to compute token & type"
  1024.             self perform: tokenType]
  1025.         ifFalse: 
  1026.             ["else just the character"
  1027.             self token: self nextChar.
  1028.             self getNextChar]! !
  1029. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  1030.  
  1031. HandCodedScanner class
  1032.     instanceVariableNames: 'charTypeTable '!
  1033.  
  1034.  
  1035. !HandCodedScanner class methodsFor: 'class initialization'!
  1036.  
  1037. initialize
  1038.     "Concrete subclasses must provide a character type table."
  1039.     "HandCodedScanner initialize"
  1040.  
  1041.     | newTable |
  1042.     newTable := Array new: 256 withAll: #xDefault.        "default"
  1043.     self charTypeTable: newTable! !
  1044.  
  1045. !HandCodedScanner class methodsFor: 'state accessing'!
  1046.  
  1047. charTypeTable
  1048.  
  1049.     ^charTypeTable!
  1050.  
  1051. charTypeTable: argument 
  1052.  
  1053.     charTypeTable := argument! !
  1054.  
  1055.  
  1056. OptimizedLookaheadScanner subclass: #OptimizedScannerWithOneTokenLookahead
  1057.     instanceVariableNames: ''
  1058.     classVariableNames: ''
  1059.     poolDictionaries: ''
  1060.     category: 'Compilers-Scanners'!
  1061.  
  1062. OptimizedScannerWithOneTokenLookahead comment:
  1063. '=================================================
  1064.     Copyright (c) 1992 by Justin O. Graver.
  1065.     All rights reserved (with exceptions).
  1066.     For complete information evaluate "Object tgenCopyright."
  1067. =================================================
  1068.  
  1069. This class provides a table-based optimized scanner with simple one-token lookahead.  '!
  1070.  
  1071. !OptimizedScannerWithOneTokenLookahead methodsFor: 'scanning'!
  1072.  
  1073. scanToken
  1074.     "Scan the next token and compute its token type."
  1075.  
  1076.     | nextState tok typeAction stateStack saveChar saveState |
  1077.     stateStack := Stack new.
  1078.     self atEnd
  1079.         ifTrue: [self signalEndOfInput]
  1080.         ifFalse:
  1081.             [stateStack push: self startState.
  1082.             [(nextState := (fsa at: stateStack top) at: self nextChar asInteger) isNil]
  1083.                 whileFalse:
  1084.                     [stateStack push: nextState.
  1085.                     self getNextChar].
  1086.             "save the current position for error notification"
  1087.             self savePosition: self position + (self atEnd ifTrue: [1] ifFalse: [0]).
  1088.             (self isFSAFinalState: stateStack top)
  1089.                 ifFalse:
  1090.                     ["save the current position for error notification"
  1091.                     saveChar := self nextChar.
  1092.                     saveState := stateStack top.
  1093.                     "backup to the previous final state or to the start state"
  1094.                     [stateStack size = 1 or: [self isFSAFinalState: stateStack top]]
  1095.                         whileFalse:
  1096.                             [stateStack pop.
  1097.                             self putBackChar].
  1098.                     stateStack size = 1
  1099.                         ifTrue:
  1100.                         ["backed up to the start state so signal an error"
  1101.                         self at: saveState transitionFor: saveChar]].
  1102.         "answer the newly scanned token"
  1103.         tok := self buffer contents.
  1104.         typeAction := self at: stateStack top tokenTypeAndActionFor: tok.
  1105.         self tokenType: typeAction type.
  1106.         self token: tok.
  1107.         self buffer reset.
  1108.         typeAction action notNil ifTrue: [self perform: typeAction action]]! !
  1109.  
  1110.  
  1111. OptimizedLookaheadScanner subclass: #OptimizedScannerWithTwoTokenLookahead
  1112.     instanceVariableNames: 'stateStack saveState saveChar '
  1113.     classVariableNames: ''
  1114.     poolDictionaries: ''
  1115.     category: 'Compilers-Scanners'!
  1116.  
  1117. OptimizedScannerWithTwoTokenLookahead comment:
  1118. '=================================================
  1119.     Copyright (c) 1992 by Justin O. Graver.
  1120.     All rights reserved (with exceptions).
  1121.     For complete information evaluate "Object tgenCopyright."
  1122. =================================================
  1123.  
  1124. This class provides a table-based optimized scanner with simple two-token lookahead.
  1125.  
  1126. Instance Variables:
  1127.     stateStack    <Stack> - primary state stack for scanning tokens.
  1128.     saveState    <Integer> - pointer into input source for error notification.
  1129.     saveChar    <Character> - pointer into input source for error notification.'!
  1130.  
  1131.  
  1132. !OptimizedScannerWithTwoTokenLookahead methodsFor: 'scanning'!
  1133.  
  1134. checkForTokenIn: newStateStack buffer: charBuffer 
  1135.     "Scan the input using the arguments. Answer true if a legal token (or no illegal token) was 
  1136.     found and false otherwise."
  1137.  
  1138.     | nextState |
  1139.     self atEnd
  1140.         ifFalse: 
  1141.             [newStateStack push: self startState.
  1142.             "look for longest possible token"
  1143.             [(nextState := (fsa at: newStateStack top) at: self nextChar asInteger) isNil]
  1144.                 whileFalse: 
  1145.                     [newStateStack push: nextState.
  1146.                     "getNextChar for local vars"
  1147.                     charBuffer nextPut: self nextChar.
  1148.                     self nextChar: self source next].
  1149.             "save the current position for error notification"
  1150.             self savePosition: self position + (self atEnd ifTrue: [1] ifFalse: [0]).
  1151.             (self isFSAFinalState: newStateStack top)
  1152.                 ifFalse: 
  1153.                     ["save the current position for error notification"
  1154.                     saveChar := self nextChar.
  1155.                     saveState := newStateStack top.
  1156.                     "backup to the previous final state or to the start state"
  1157.                     [newStateStack size = 1 or: [self isFSAFinalState: newStateStack top]]
  1158.                         whileFalse: 
  1159.                             [newStateStack pop.
  1160.                             "putBackChar for local vars"
  1161.                             charBuffer backspace.
  1162.                             self backspaceSource].
  1163.                     newStateStack size = 1 ifTrue: 
  1164.                         ["backed up to the start state"
  1165.                         self stateStack == newStateStack
  1166.                             ifTrue: 
  1167.                                 ["this is the first token, so signal an error (abort and return)"
  1168.                                 self at: saveState transitionFor: saveChar]
  1169.                             ifFalse: 
  1170.                                 ["we may be able to backup in the previous token"
  1171.                                 ^false]]]].
  1172.     ^true!
  1173.  
  1174. scanToken
  1175.     "Scan the next token and compute its token type."
  1176.  
  1177.     | tok typeAction newStateStack charBuffer |
  1178.     newStateStack := Stack new.
  1179.     charBuffer := RetractableWriteStream on: (String new: 32).
  1180.     (self checkForTokenIn: newStateStack buffer: charBuffer)
  1181.         ifTrue: 
  1182.             ["either a legal token or the end on input was found"
  1183.             self stateStack isEmpty ifTrue: [self atEnd
  1184.                     ifTrue: [^self signalEndOfInput]
  1185.                     ifFalse: [self error: 'no more vaild tokens']].
  1186.             tok := self buffer contents.
  1187.             typeAction := self at: stateStack top tokenTypeAndActionFor: tok.
  1188.             self tokenType: typeAction type.
  1189.             self token: tok.
  1190.             self buffer: charBuffer.
  1191.             self stateStack: newStateStack.
  1192.             typeAction action notNil ifTrue: [self perform: typeAction action]]
  1193.         ifFalse: 
  1194.             ["an illegal token was found, try to look for earlier final state in current token buffers"
  1195.             charBuffer size timesRepeat: 
  1196.                 ["put back illegal token chars"
  1197.                 self backspaceSource].
  1198.             "backup in current token to next smallest legal token"
  1199.             [self stateStack size = 1
  1200.                 or: 
  1201.                     [self stateStack pop.
  1202.                     self putBackChar.
  1203.                     self isFSAFinalState: stateStack top]] whileFalse.
  1204.             self stateStack size = 1
  1205.                 ifTrue: 
  1206.                     ["no smaller legal token so signal error"
  1207.                     self at: saveState transitionFor: saveChar]
  1208.                 ifFalse: 
  1209.                     ["try again"
  1210.                     self scanToken]]! !
  1211.  
  1212. !OptimizedScannerWithTwoTokenLookahead methodsFor: 'initialization'!
  1213.  
  1214. reset
  1215.     "Reset the initial state of the scanner before scanning a new source."
  1216.  
  1217.     super reset.
  1218.     self stateStack: Stack new!
  1219.  
  1220. scanSource: aString 
  1221.     "Convert the input string to a read stream and scan the first token."
  1222.  
  1223.     self reset.
  1224.     self source: (RetractableReadStream on: aString).
  1225.     self nextChar: self source next.
  1226.     self checkForTokenIn: self stateStack buffer: self buffer.
  1227.     self scanToken! !
  1228.  
  1229. !OptimizedScannerWithTwoTokenLookahead methodsFor: 'state accessing'!
  1230.  
  1231. saveChar
  1232.  
  1233.     ^saveChar!
  1234.  
  1235. saveChar: argument 
  1236.  
  1237.     saveChar := argument!
  1238.  
  1239. saveState
  1240.  
  1241.     ^saveState!
  1242.  
  1243. saveState: argument 
  1244.  
  1245.     saveState := argument!
  1246.  
  1247. stateStack
  1248.  
  1249.     ^stateStack!
  1250.  
  1251. stateStack: argument 
  1252.  
  1253.     stateStack := argument! !
  1254.  
  1255.  
  1256. FSABasedScanner initialize!
  1257. HandCodedScanner initialize!
  1258. OptimizedScanner initialize!
  1259.